#include "user_uart3.h"

#include "Serial_Port_Analysis.h"//添加串口解析命令头文件



#define SAMPLE_UART_NAME    "uart3"                 // 串口设备名称
#define RCV_BUFF_SIZE_MAX   1024                    // 接收最大字节长度

static struct rt_semaphore rx_sem;                  // 用于接收消息的信号量
static rt_device_t serial;                          // 串口设备句柄
static rt_thread_t serial_recv_thread;              // 串口接收线程句柄

static char serial_recv_buff[RCV_BUFF_SIZE_MAX];    // 串口接收缓存区
static char serial_recv_flag;                       // 串口接收标志
static int  serial_recv_length;                     // 接收字节长度


//
/* 消息队列控制块 */
extern struct rt_messagequeue oled_mq;
/* 消息队列中用到的放置消息的内存池 */
extern rt_uint8_t oled_msg_pool[2048];
//


//定义一个函数，用于解析重量协议数据包
void parse_weight_protocol(uint8_t *data, int len) 
{
      /* 协议解析 */          
            const char* hex_str = data;
            PacketList packets = split_packets(hex_str, len);
            int j = 0;
            // // 解析并打印结果
            for (size_t i = 0; i < packets.count; ++i) {
                j++;
                rt_kprintf("==== 数据包 %d ====\n", j);
                ParsedPacket pkt = parse_packet(packets.packets[i].data, packets.packets[i].length);
                print_packet(&pkt);
            }
            // // 释放内存
            for (size_t i = 0; i < packets.count; ++i) {
                free(packets.packets[i].data);
            }
            free(packets.packets);     

         
}


/* ====================串口发送和打印线程=================== */

#define THREAD_PRIORITY         25      // 线程优先级
#define THREAD_STACK_SIZE       4096    // 线程大小
#define THREAD_TIMESLICE        20      // 时间片

static rt_thread_t serial_thread = RT_NULL;   // 线程控制块


// 中断接收回调函数
static rt_err_t uart_input(rt_device_t dev, rt_size_t size)
{
    /* 串口有数据传入后产生中断，调用此回调函数，释放信号量 */
    if (size > 0)
        rt_sem_release(&rx_sem);

    return RT_EOK;
}

// 串口接收线程入口函数
static void serial_recv_thread_entry(void *param)
{
    rt_kprintf("\nserial_recv_thread_entry run ......\n");
    while(1)
    {
        char temp_recv_buff = 0; // 接收临时缓存区
        int ret = rt_device_read(serial, 0, &temp_recv_buff, 1);
        if(ret < 0) // 出现了错误
        {
            pr_debug("read() return [%ld] %s\n", rt_get_errno(), rt_strerror(rt_get_errno()));
        }
        if(ret == 0) // 未接到数据
        {
            // 重置信号量
            rt_sem_control(&rx_sem, RT_IPC_CMD_RESET, RT_NULL);
            // 获取信号量，如果没有获取得到则阻塞在这里永远等待。
            rt_sem_take(&rx_sem, RT_WAITING_FOREVER);
        }

        if(ret == 1) // 接收到1字节的数据
        {
            // 防止数据超出缓存区的大小
            if(serial_recv_length < RCV_BUFF_SIZE_MAX - 1)
            {
                // 存入接收缓存区并递增长度
                serial_recv_buff[serial_recv_length++] = temp_recv_buff;
                // rt_kprintf("%x\n", temp_recv_buff); // 打印接收到的字节，用于调试
            }
            else
            {
                // 如果缓冲区已满，则从0开始覆盖旧数据
                serial_recv_length = 0;
                serial_recv_buff[serial_recv_length++] = temp_recv_buff;
            }
            // 为接收缓存区最后添加 '\0'
            serial_recv_buff[serial_recv_length] = '\0';
            // 设置串口接收完成标志
            serial_recv_flag = 1;
        }
    }
}

/************************************************
函数名称 ： Clear_recv_buff
功    能 ： 清空串口接收缓存区
参    数 ： 无
返 回 值 ：
作    者 ： LC
*************************************************/
static void Clear_recv_buff(void)
{
    // 清空接收缓存区
    rt_memset(serial_recv_buff, 0, sizeof(serial_recv_buff));

    // 清空标志位
    serial_recv_flag = 0;

    // 清空缓存区长度计量
    serial_recv_length = 0;
}

/************************************************
函数名称 ： serial_send_byte
功    能 ： 串口发送一个字节
参    数 ： 发送的数据
返 回 值 ： RT_EOK成功   -RT_ERROR失败
作    者 ： LC
*************************************************/
static int Serial_Send_Byte(uint8_t dat)
{
    int ret = rt_device_write(serial, 0, &dat, 1);
    if(ret != 1)
    {
        LOG_E("Failed to [Serial_Send_Byte] code[%d] !!!", ret);
        return -RT_ERROR;
    }

    return RT_EOK;
}

/************************************************
函数名称 ： Serial_Send_String
功    能 ： 串口发送字符串
参    数 ： data_buff缓存区地址
返 回 值 ： RT_EOK成功   -RT_ERROR失败
作    者 ： LCKFB
*************************************************/
int Serial_Send_String(uint8_t *data_buff)
{
    int err_count = 0;

    /* 地址为空 或者 值为空 跳出 */
    while(data_buff && *data_buff)
    {
        if(RT_EOK != Serial_Send_Byte(*data_buff++))
        {
            err_count++;
            continue;
        }
    }

    /* 如果err_count不为0，则说明发送的时候有错误！！！ */
    if(err_count)
    {
        LOG_E("serial_send_string failed !!!");
        return -RT_ERROR;
    }

    return RT_EOK;
}

/******************************************************************
 * 函 数 名 称：Serial_Recv_DATA
 * 函 数 说 明：接串口的数据
 * 函 数 形 参：data_buff数据缓存区
 * 函 数 返 回： 0：  未接收到数据
 *             其他： 接收到的数据长度
 * 作       者：LCKFB
 * 备       注：无
******************************************************************/
int Serial_Recv_DATA(uint8_t *data_buff)
{
    int i;

    /* 判断是否接到了数据 */
    if((serial_recv_flag != 1) || (serial_recv_length == 0))
    {
        /* 未接到 */
        return 0;
    }

    /* 将数据转存到指针指向的地址中 */
    for(i = 0; i < serial_recv_length; i++)
    {
        data_buff[i] = serial_recv_buff[i];
    }

    /* 加入字符串结尾 */
    data_buff[i] = '\0';

    /* 清除接收的数据、标志位和数据长度。 */
    Clear_recv_buff();

    return i; // 返回接收到的数据长度
}

/************************************************
函数名称 ： UART_Init
功    能 ： 串口初始化
参    数 ： 无
返 回 值 ： RT_EOK成功   -RT_ERROR失败
作    者 ： LCKFB
*************************************************/
static int UART_Init(void)
{
    int ret = 0;

    // 清空接收缓存区
    rt_memset(serial_recv_buff,0,sizeof(serial_recv_buff));

    // 清空标志位
    serial_recv_flag = 0;

    // 清空缓存区长度计量
    serial_recv_length = 0;

    rt_kprintf("Try to open(%s)\n", SAMPLE_UART_NAME);

    // 获取串口句柄
    serial = rt_device_find(SAMPLE_UART_NAME);
    if (!serial)
    {
        LOG_E("find %s failed!\n", SAMPLE_UART_NAME);

        return -RT_ERROR;
    }

    // 初始化信号量
    ret = rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);
    if (ret != RT_EOK)
    {
        LOG_E("failed to rt_sem_init !\n");
        return -RT_ERROR;
    }

    // 打开串口设备
    ret = rt_device_open(serial, RT_DEVICE_FLAG_INT_RX);
    if (ret != RT_EOK)
    {
        LOG_E("open %s failed : %d !\n", SAMPLE_UART_NAME, ret);
        return -RT_ERROR;
    }

    // 设置接收回调函数
    rt_device_set_rx_indicate(serial, uart_input);

    // 创建串口数据接收线程
    serial_recv_thread = rt_thread_create("serial", serial_recv_thread_entry, RT_NULL, 1024*2, 15, 20);
    if (serial_recv_thread != RT_NULL)
    {
        // 启动线程
        rt_thread_startup(serial_recv_thread);
    }
    else
    {
        rt_device_close(serial);
        LOG_E("Failed to [rt_thread_create] !!!");
        return -RT_ERROR;
    }

    return RT_EOK;
}
#include <oled.h>



// 线程入口函数// 修改serial3_thread_entry函数
static void serial3_thread_entry(void *param)
{
  // 定义一个无符号8位整数变量run_time，用于记录运行时间
  uint8_t run_time = 0;
  // 无限循环，程序会一直运行在这个循环中
    while(1) {
      // 每次循环run_time加1，用于记录循环次数或时间
        run_time++;
      // 定义一个无符号8位整数数组recv_buff，大小为256，用于存储接收到的数据，并初始化为0
        uint8_t recv_buff[256] = {0};
      // 调用Serial_Recv_DATA函数接收数据，接收到的数据存储在recv_buff中，返回接收到的数据个数
        int count = Serial_Recv_DATA(recv_buff);

      // 如果接收到的数据个数大于0，表示有数据接收成功
        if (count > 0) {
            /* 原始数据打印（调试用） */
            rt_kprintf("Raw: ");    // 使用rt_kprintf函数打印接收缓冲区中的数据
            for(int i=0; i<count; i++) {
                rt_kprintf("%02X ", recv_buff[i]);// "%02X"是格式化字符串，表示以两位十六进制数的形式输出
            }
            rt_kprintf("\n");   // recv_buff[i]表示接收缓冲区中的第i个字节

            
            /* 协议解析，解析串口数据包 */       
            parse_weight_protocol(recv_buff, count);
            // rt_kprintf("解析数据包\n");
        }
        rt_thread_mdelay(20); // 缩短延迟提高响应速度
    }
}


// 数据发送函数
// 定义一个静态函数 send_demoData，用于发送演示数据
// 参数 argc 表示命令行参数的数量，argv 是一个指向字符串数组的指针，每个字符串是一个命令行参数
static void send_demoData(int argc, char **argv)
{
    // 定义一个静态变量 num，用于记录发送次数，静态变量在函数调用间保持其值
    static int num = 1;
    // 定义一个 uint8_t 类型的数组 Send_Buff，用于存储要发送的数据，初始化为一段字符串
    uint8_t Send_Buff[128] = {"立创·衡山派D133EBS开发板 * UART框架使用测试"};
    // 定义一个整型变量 ret，用于存储发送函数的返回值
    int ret = 0;
    // 定义一个字符数组 buffer，用于存储格式化后的发送字符串，初始化为 0
    char buffer[128] = {0};

    // 使用 snprintf 来格式化要发送的字符串Send_Buff
    snprintf(buffer, sizeof(buffer), "【%d】%s", num, (argc == 2) ? *(argv+1) : (char *)Send_Buff);

    // 发送数据
    ret = Serial_Send_String((uint8_t *)buffer);

    if(ret != RT_EOK)
    {
        LOG_E("%s: The test data transmission failed.", __FUNCTION__);
    }
    else
    {
        rt_kprintf("\n[%d] Send success\n", num);
        num++; // 只有发送成功时才递增 num
    }
}

// 导出函数为命令
MSH_CMD_EXPORT(send_demoData, Send test data);

// 串口接收和发送线程开启
static void uart3_test_on(int argc, char **argv)
{
    int ret = UART_Init();  // 串口初始化
    if(ret != RT_EOK)
    {
        LOG_E("Failed to [UART_Init] !!!");
        LOG_E("file: %s line: %d", __FILE__, __LINE__);
        return;
    }
    rt_kprintf("UART3_Init OK!!\n");

    /* 创建线程，名称是 serial3_thread，入口是 serial3_thread_entry */
    serial_thread = rt_thread_create("serial3_thread",
                            serial3_thread_entry, RT_NULL,
                            THREAD_STACK_SIZE,
                            THREAD_PRIORITY, THREAD_TIMESLICE);

    /* 如果获得线程控制块，启动这个线程 */
    if (serial_thread != RT_NULL)
        rt_thread_startup(serial_thread);

    rt_kprintf("Test transmission and reception using UART3 serial port!!\n");
}

// //使用命令开启线程// 导出函数为命令
// MSH_CMD_EXPORT(uart3_test_on, Test transmission and reception using UART3 serial port);

// 导出函数自动运行，在系统初始化时调用uart3_test_on函数
INIT_APP_EXPORT(uart3_test_on);